package com.tsfyun.scm.service.impl.logistics;

import cn.hutool.core.lang.Snowflake;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.enums.BillTypeEnum;
import com.tsfyun.common.base.enums.SerialNumberTypeEnum;
import com.tsfyun.common.base.enums.domain.*;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.support.DomainStatus;
import com.tsfyun.common.base.util.LocalDateTimeUtils;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.dto.logistics.DeliveryConfirmDTO;
import com.tsfyun.scm.dto.logistics.DeliveryDepartureDTO;
import com.tsfyun.scm.dto.logistics.DeliverySignDTO;
import com.tsfyun.scm.dto.logistics.DeliveryWaybillQTO;
import com.tsfyun.scm.dto.support.TaskNoticeContentDTO;
import com.tsfyun.scm.entity.logistics.*;
import com.tsfyun.scm.entity.order.ImpOrder;
import com.tsfyun.scm.entity.order.ImpOrderLogistics;
import com.tsfyun.scm.entity.order.ImpOrderMember;
import com.tsfyun.scm.mapper.logistics.DeliveryWaybillMapper;
import com.tsfyun.scm.service.file.IUploadFileService;
import com.tsfyun.scm.service.logistics.*;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.service.order.IImpOrderLogisticsService;
import com.tsfyun.scm.service.order.IImpOrderMemberService;
import com.tsfyun.scm.service.support.ITaskNoticeContentService;
import com.tsfyun.scm.service.system.ISerialNumberService;
import com.tsfyun.scm.service.system.IStatusHistoryService;
import com.tsfyun.scm.vo.logistics.DeliveryWaybillMemberVO;
import com.tsfyun.scm.vo.logistics.DeliveryWaybillPlusVO;
import com.tsfyun.scm.vo.logistics.DeliveryWaybillVO;
import com.tsfyun.scm.vo.order.ImpOrderLogisticsVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 送货单 服务实现类
 * </p>
 *

 * @since 2020-05-25
 */
@Service
public class DeliveryWaybillServiceImpl extends ServiceImpl<DeliveryWaybill> implements IDeliveryWaybillService {

    @Autowired
    private DeliveryWaybillMapper deliveryWaybillMapper;
    @Autowired
    private ISerialNumberService serialNumberService;
    @Autowired
    private IImpOrderLogisticsService impOrderLogisticsService;
    @Autowired
    private IImpOrderMemberService impOrderMemberService;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private IDeliveryWaybillMemberService deliveryWaybillMemberService;
    @Autowired
    private IStatusHistoryService statusHistoryService;
    @Autowired
    private ICrossBorderWaybillService crossBorderWaybillService;
    @Autowired
    private ITransportSupplierService transportSupplierService;
    @Autowired
    private IConveyanceService conveyanceService;
    @Autowired
    private ITaskNoticeContentService taskNoticeContentService;
    @Autowired
    private IUploadFileService uploadFileService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createByImpOrder(ImpOrder impOrder) {
        ImpOrderLogistics logistics = impOrderLogisticsService.getById(impOrder.getId());
        DeliveryWaybill dw = new DeliveryWaybill();
        dw.setId(snowflake.nextId());
        dw.setDocNo(serialNumberService.generateDocNo(SerialNumberTypeEnum.DELIVERY_WAYBILL));
        dw.setMemo(StringUtils.removeSpecialSymbol(logistics.getDeliveryModeMemo()));
        dw.setCustomerId(impOrder.getCustomerId());
        dw.setImpOrderId(impOrder.getId());
        dw.setImpOrderNo(impOrder.getDocNo());
        dw.setTransDate(LocalDateTimeUtils.convertLocalDate());
        DeliveryWaybillStatusEnum statusEnum = DeliveryWaybillStatusEnum.INITIAL;
        dw.setStatusId(statusEnum.getCode());
        dw.setBillType(BillTypeEnum.IMP.getCode());
        dw.setReceivingMode(logistics.getReceivingMode());
        dw.setReceivingModeName(logistics.getReceivingModeName());
        super.saveNonNull(dw);

        List<ImpOrderMember>  memberList = impOrderMemberService.getByOrderId(impOrder.getId());
        List<DeliveryWaybillMember> waybillMemberList = Lists.newArrayList();
        memberList.stream().forEach(member ->{
            DeliveryWaybillMember dwm = new DeliveryWaybillMember();
            dwm.setId(snowflake.nextId());
            dwm.setDeliveryNoteId(dw.getId());
            dwm.setOrderMemberId(member.getId());
            dwm.setQuantity(member.getQuantity());
            waybillMemberList.add(dwm);
        });
        deliveryWaybillMemberService.savaBatch(waybillMemberList);

        //记录历史状态
        statusHistoryService.saveHistory(DomainOprationEnum.DELIVERY_WAYBILL_ADD,
                dw.getId().toString(),DeliveryWaybill.class.getName(),
                statusEnum.getCode(),statusEnum.getName(),"根据订单生成","系统");
    }

    @Override
    public PageInfo<DeliveryWaybillVO> pageList(DeliveryWaybillQTO qto) {
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        Map<String,Object> params = beanMapper.map(qto,Map.class);
        List<DeliveryWaybillVO> list = deliveryWaybillMapper.list(params);
        return new PageInfo<>(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmByOrder(Long orderId) {
        List<DeliveryWaybill> deliveryWaybills = findByOrderId(orderId);
        deliveryWaybills.stream().forEach(dw ->{
            DeliveryWaybillStatusEnum historyStatus = DeliveryWaybillStatusEnum.of(dw.getStatusId());
            if(Objects.equals(DeliveryWaybillStatusEnum.INITIAL,historyStatus)){
                //第三方物流和专车送货 需要确定
                if("ThirdLogistics".equals(dw.getReceivingMode()) || "SpecialCar".equals(dw.getReceivingMode())){
                    DeliveryWaybillStatusEnum nowStatus = DeliveryWaybillStatusEnum.WAIT_CONFIRM;//待确认
                    dw.setStatusId(nowStatus.getCode());
                    super.updateById(dw);
                    //记录历史状态
                    statusHistoryService.saveHistory(DomainOprationEnum.DECLARATION_COMPLETED,
                            dw.getId().toString(),DeliveryWaybill.class.getName(),
                            historyStatus.getCode(),historyStatus.getName(),
                            nowStatus.getCode(),nowStatus.getName(),
                            "报关单申报成功，自动触发","系统");

                    //发送通知
                    TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
                    taskNoticeContentDTO.setDocumentType(DomainTypeEnum.DELIVERYWAYBILL.getCode());
                    taskNoticeContentDTO.setDocumentId(dw.getId().toString());
                    taskNoticeContentDTO.setCustomerId(dw.getCustomerId());//客户
                    taskNoticeContentDTO.setOperationCode(DomainOprationEnum.DELIVERY_WAYBILL_CONFIRM.getCode());
                    taskNoticeContentDTO.setContent(String.format("国内送货单【%s】需要您确认。",dw.getDocNo()));
                    taskNoticeContentDTO.setQueryParamsMap(ImmutableMap.of("docNo",dw.getDocNo()));
                    taskNoticeContentService.add(taskNoticeContentDTO);
                }
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void driveByCrossBorderWaybill(CrossBorderWaybill crossBorderWaybill, Long orderId) {
        List<DeliveryWaybill> deliveryWaybills = findByOrderId(orderId);
        deliveryWaybills.stream().forEach(dw ->{
            DeliveryWaybillStatusEnum historyStatus = DeliveryWaybillStatusEnum.of(dw.getStatusId());
            DeliveryWaybillStatusEnum nowStatus = null;
            if("SelfLifting".equals(dw.getReceivingMode()) || "ThirdLogistics".equals(dw.getReceivingMode()) || "SpecialCar".equals(dw.getReceivingMode())){
                dw.setWarehouseId(crossBorderWaybill.getDeliveryWareId());
                dw.setShippingCompany(crossBorderWaybill.getDeliveryCompany());
                dw.setShippingAddress(crossBorderWaybill.getDeliveryAddress());
                dw.setShippingLinkMan(crossBorderWaybill.getDeliveryLinkPerson());
                dw.setShippingTel(crossBorderWaybill.getDeliveryLinkTel());
            }
            //自提
            if("SelfLifting".equals(dw.getReceivingMode())){
                nowStatus = DeliveryWaybillStatusEnum.WAIT_SIGN;//待签收
                dw.setStatusId(nowStatus.getCode());
            }
            //港车直送
            if("HkThrough".equals(dw.getReceivingMode())){
                dw.setWarehouseId(crossBorderWaybill.getShippingWareId());
                dw.setShippingCompany(crossBorderWaybill.getShippingCompany());
                dw.setShippingAddress(crossBorderWaybill.getShippingAddress());
                dw.setShippingLinkMan(crossBorderWaybill.getShippingLinkPerson());
                dw.setShippingTel(crossBorderWaybill.getShippingLinkTel());

                dw.setTransportSupplierId(crossBorderWaybill.getTransportSupplierId());
                dw.setConveyanceId(crossBorderWaybill.getConveyanceId());
                dw.setConveyanceNo(crossBorderWaybill.getConveyanceNo());
                dw.setConveyanceNo2(crossBorderWaybill.getConveyanceNo2());
                dw.setDriverInfo(crossBorderWaybill.getDriverInfo());

                dw.setDepartureDate(crossBorderWaybill.getDepartureDate());
                dw.setSealNo(crossBorderWaybill.getSealNo());

                nowStatus = DeliveryWaybillStatusEnum.WAIT_SIGN;//待签收
                dw.setStatusId(nowStatus.getCode());
            }
            super.updateById(dw);
            if(Objects.nonNull(nowStatus) && !Objects.equals(historyStatus,nowStatus)){
                //记录历史状态
                statusHistoryService.saveHistory(DomainOprationEnum.CROSS_BORDER_WAYBILL_DEPART,
                        dw.getId().toString(),DeliveryWaybill.class.getName(),
                        historyStatus.getCode(),historyStatus.getName(),
                        nowStatus.getCode(),nowStatus.getName(),
                        "跨境运单发车成功，自动触发","系统");
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void signByCrossBorderWaybill(CrossBorderWaybill crossBorderWaybill, Long orderId) {
        List<DeliveryWaybill> deliveryWaybills = findByOrderId(orderId);
        deliveryWaybills.stream().forEach(dw ->{
            DeliveryWaybillStatusEnum historyStatus = DeliveryWaybillStatusEnum.of(dw.getStatusId());
            DeliveryWaybillStatusEnum nowStatus = DeliveryWaybillStatusEnum.SIGNED;
            //港车直送
            if("HkThrough".equals(dw.getReceivingMode())&&Objects.equals(DeliveryWaybillStatusEnum.WAIT_SIGN,historyStatus)){
                dw.setReachDate(crossBorderWaybill.getReachDate());
                dw.setStatusId(nowStatus.getCode());
                super.updateById(dw);
                //记录历史状态
                statusHistoryService.saveHistory(DomainOprationEnum.CROSS_BORDER_WAYBILL_SIGN,
                        dw.getId().toString(),DeliveryWaybill.class.getName(),
                        historyStatus.getCode(),historyStatus.getName(),
                        nowStatus.getCode(),nowStatus.getName(),
                        "跨境运单签收成功");
            }
        });
    }

    @Override
    public List<DeliveryWaybill> findByOrderId(Long orderId) {
        if(Objects.isNull(orderId)){return Lists.newArrayList();}
        DeliveryWaybill query = new DeliveryWaybill();
        query.setImpOrderId(orderId);
        return deliveryWaybillMapper.select(query);
    }

    @Override
    public DeliveryWaybillPlusVO detail(Long id, String operation) {
        DeliveryWaybillVO deliveryWaybill = deliveryWaybillMapper.detail(id);
        TsfPreconditions.checkArgument(Objects.nonNull(deliveryWaybill),new ServiceException("送货单不存在"));
        //验证状态是否可以执行操作
        DomainStatus.getInstance().check(DomainOprationEnum.of(operation), deliveryWaybill.getStatusId());
        ImpOrderLogisticsVO logisticsVO = impOrderLogisticsService.findById(deliveryWaybill.getImpOrderId());
        List<DeliveryWaybillMemberVO> memberVOS = deliveryWaybillMemberService.findByDeliveryId(deliveryWaybill.getId());
        return new DeliveryWaybillPlusVO(deliveryWaybill,logisticsVO,memberVOS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirm(DeliveryConfirmDTO dto) {
        DeliveryWaybill deliveryWaybill = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(deliveryWaybill),new ServiceException("送货单不存在"));
        //验证状态是否可以执行操作
        DomainOprationEnum oprationEnum = DomainOprationEnum.DELIVERY_WAYBILL_CONFIRM;
        DomainStatus.getInstance().check(oprationEnum, deliveryWaybill.getStatusId());
        switch (deliveryWaybill.getReceivingMode()){
            case "ThirdLogistics"://第三方物流
                deliveryWaybill.setExperssNo(StringUtils.removeAllSpecialChar(dto.getExperssNo()).replace("，",","));
                break;
            case "SpecialCar"://专车送货
                if(Objects.nonNull(dto.getTransportSupplierId())){
                    //运输供应商
                    TransportSupplier transportSupplier = transportSupplierService.getById(dto.getTransportSupplierId());
                    TsfPreconditions.checkArgument(Objects.nonNull(transportSupplier) && Objects.equals(transportSupplier.getDisabled(),Boolean.FALSE),new ServiceException("运输供应商不存在或已被禁用"));
                    deliveryWaybill.setTransportSupplierId(transportSupplier.getId());
                }
                if(Objects.nonNull(dto.getConveyanceId())){
                    //运输工具
                    Conveyance conveyance = conveyanceService.getById(dto.getConveyanceId());
                    TsfPreconditions.checkArgument(Objects.nonNull(conveyance) && Objects.equals(conveyance.getDisabled(),Boolean.FALSE),new ServiceException("运输工具不存在或已被禁用"));
                    deliveryWaybill.setConveyanceId(conveyance.getId());
                    deliveryWaybill.setConveyanceNo(conveyance.getConveyanceNo());
                    deliveryWaybill.setConveyanceNo2(conveyance.getConveyanceNo2());
                    //司机信息
                    deliveryWaybill.setDriverInfo(String.format("%s %s %s",StringUtils.null2EmptyWithTrim(conveyance.getDriver()),StringUtils.null2EmptyWithTrim(conveyance.getDriverTel()), StringUtils.null2EmptyWithTrim(conveyance.getDriverNo())));
                }
                break;
            default:
                throw new ServiceException("当前送货方式不需要确认");
        }
        DeliveryWaybillStatusEnum historyStatus = DeliveryWaybillStatusEnum.of(deliveryWaybill.getStatusId());
        DeliveryWaybillStatusEnum nowStatus = DeliveryWaybillStatusEnum.WAIT_DEPART;//待发车
        deliveryWaybill.setStatusId(nowStatus.getCode());
        super.updateById(deliveryWaybill);

        //记录历史状态
        statusHistoryService.saveHistory(oprationEnum,
                deliveryWaybill.getId().toString(),DeliveryWaybill.class.getName(),
                historyStatus.getCode(),historyStatus.getName(),
                nowStatus.getCode(),nowStatus.getName(),
                "运输单已确认");
        //清空任务
        clearTaskNotice(deliveryWaybill.getId());
        //发送通知
        TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
        taskNoticeContentDTO.setDocumentType(DomainTypeEnum.DELIVERYWAYBILL.getCode());
        taskNoticeContentDTO.setDocumentId(deliveryWaybill.getId().toString());
        taskNoticeContentDTO.setCustomerId(deliveryWaybill.getCustomerId());//客户
        taskNoticeContentDTO.setOperationCode(DomainOprationEnum.DELIVERY_WAYBILL_DEPART.getCode());
        taskNoticeContentDTO.setContent(String.format("国内送货单【%s】备货完成后，请尽快完成发车。",deliveryWaybill.getDocNo()));
        taskNoticeContentDTO.setQueryParamsMap(ImmutableMap.of("docNo",deliveryWaybill.getDocNo()));
        taskNoticeContentService.add(taskNoticeContentDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmDeparture(DeliveryDepartureDTO dto) {
        DeliveryWaybill deliveryWaybill = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(deliveryWaybill),new ServiceException("送货单不存在"));
        //验证状态是否可以执行操作
        DomainOprationEnum oprationEnum = DomainOprationEnum.DELIVERY_WAYBILL_DEPART;
        DomainStatus.getInstance().check(oprationEnum, deliveryWaybill.getStatusId());
        switch (deliveryWaybill.getReceivingMode()){
            case "ThirdLogistics"://第三方物流
                deliveryWaybill.setExperssNo(StringUtils.removeAllSpecialChar(dto.getExperssNo()).replace("，",","));
                break;
            case "SpecialCar"://专车送货
                deliveryWaybill.setSealNo(StringUtils.removeAllSpecialChar(dto.getSealNo()));
                break;
            default:
                throw new ServiceException("当前送货方式不需做发车确认");
        }
        //验证港车是否到达
        CrossBorderWaybill cbw = crossBorderWaybillService.findByImpOrderId(deliveryWaybill.getImpOrderId());
        TsfPreconditions.checkArgument(Objects.nonNull(cbw),new ServiceException("未找订单对应的跨境运单"));
        if(!Objects.equals(CrossBorderWaybillStatusEnum.SIGNED,CrossBorderWaybillStatusEnum.of(cbw.getStatusId()))){
            throw new ServiceException(String.format("跨境运单【%s】还未签收，请先签收",cbw.getDocNo()));
        }

        deliveryWaybill.setDepartureDate(dto.getDepartureDate());//发车时间
        DeliveryWaybillStatusEnum historyStatus = DeliveryWaybillStatusEnum.of(deliveryWaybill.getStatusId());
        DeliveryWaybillStatusEnum nowStatus = DeliveryWaybillStatusEnum.WAIT_SIGN;//待签收
        deliveryWaybill.setStatusId(nowStatus.getCode());
        super.updateById(deliveryWaybill);

        //记录历史状态
        statusHistoryService.saveHistory(oprationEnum,
                deliveryWaybill.getId().toString(),DeliveryWaybill.class.getName(),
                historyStatus.getCode(),historyStatus.getName(),
                nowStatus.getCode(),nowStatus.getName(),
                "运输单已发车");

        //清空任务
        clearTaskNotice(deliveryWaybill.getId());
        //发送通知
        TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
        taskNoticeContentDTO.setDocumentType(DomainTypeEnum.DELIVERYWAYBILL.getCode());
        taskNoticeContentDTO.setDocumentId(deliveryWaybill.getId().toString());
        taskNoticeContentDTO.setCustomerId(deliveryWaybill.getCustomerId());//客户
        taskNoticeContentDTO.setOperationCode(DomainOprationEnum.DELIVERY_WAYBILL_SIGN.getCode());
        taskNoticeContentDTO.setContent(String.format("国内送货单【%s】已发车，客户收到货后请尽快完成签收动作。",deliveryWaybill.getDocNo()));
        taskNoticeContentDTO.setQueryParamsMap(ImmutableMap.of("docNo",deliveryWaybill.getDocNo()));
        taskNoticeContentService.add(taskNoticeContentDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmSign(DeliverySignDTO dto) {
        DeliveryWaybill deliveryWaybill = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(deliveryWaybill),new ServiceException("送货单不存在"));
        //验证状态是否可以执行操作
        DomainOprationEnum oprationEnum = DomainOprationEnum.DELIVERY_WAYBILL_SIGN;
        DomainStatus.getInstance().check(oprationEnum, deliveryWaybill.getStatusId());

        if("HkThrough".equals(deliveryWaybill.getReceivingMode())){
            throw new ServiceException("港车直送请在跨境运输做签收确认");
        }

        deliveryWaybill.setReachDate(dto.getReachDate());//签收时间
        DeliveryWaybillStatusEnum historyStatus = DeliveryWaybillStatusEnum.of(deliveryWaybill.getStatusId());
        DeliveryWaybillStatusEnum nowStatus = DeliveryWaybillStatusEnum.SIGNED;//已签收
        deliveryWaybill.setStatusId(nowStatus.getCode());
        super.updateById(deliveryWaybill);

        //记录历史状态
        statusHistoryService.saveHistory(oprationEnum,
                deliveryWaybill.getId().toString(),DeliveryWaybill.class.getName(),
                historyStatus.getCode(),historyStatus.getName(),
                nowStatus.getCode(),nowStatus.getName(),
                "运输单已签收");
        //清空任务
        clearTaskNotice(deliveryWaybill.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAllById(Long id) {
        //删除送货单明细数据
        deliveryWaybillMemberService.removeByDeliveryId(id);
        //删除历史状态
        statusHistoryService.removeHistory(id.toString(),DeliveryWaybill.class.getName());
        //删除文件信息
        uploadFileService.deleteByDocId(id.toString());
        //删除主单
        super.removeById(id);
        //清空任务
        clearTaskNotice(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeByOrderId(Long orderId) {
        List<DeliveryWaybill> waybillList = findByOrderId(orderId);
        waybillList.stream().forEach(waybill ->{
            removeAllById(waybill.getId());
        });
    }

    //清空任务通知
    public void clearTaskNotice(Long id){
        taskNoticeContentService.deleteTaskNotice(DomainTypeEnum.DELIVERYWAYBILL.getCode(), id, "");
    }

}
